package com.zues.rabbit_springboot_consumer.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

/**
 * @ClassName RejectListener
 * @Description 消息拒绝后重试测试类
 * @Author zeus
 * @Date 7/10/2025 5:39 下午
 * @Version 1.0
 **/
@Component
@Slf4j
public class RejectRetryListener {

    private static final String QUEUE_ERROR_RETRY = "queue.error.retry";

    /**
     * 监听指定的队列，消费消息
     * 消费消息造成消息超时，会触发重试机制，重试次数由spring.rabbitmq.listener.simple.retry.max-attempts配置决定
     * 重试间隔时间由spring.rabbitmq.listener.simple.retry.initial-interval配置决定
     *
     * @param dataString 消息内容
     * @param message    消息对象
     * @param channel    通道对象
     * @throws IOException 异常
     */
    @RabbitListener(queues = QUEUE_ERROR_RETRY)
    public void processMessage(String dataString, Message message, Channel channel) throws IOException {

        //DeliveryTag: 每条消息在队列中的唯一标识
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            //核心操作
            log.info("消费端接受到了消息： {}", dataString);
            log.info("队列： {}", message.getMessageProperties().getConsumerQueue());
            log.info("交换机： {}", message.getMessageProperties().getReceivedExchange());
            log.info("routingKey： {}", message.getMessageProperties().getReceivedRoutingKey());


            // 核心操作成功，返回 ACK 信息
//            channel.basicAck(deliveryTag, false);
            throw new RuntimeException("测试消息拒绝后重试机制");
        } catch (Exception e) {
            log.error("死信消费端处理消息失败：{}", e.getMessage());
            // 获取当前消息是否重复投递的
            Boolean redelivered = message.getMessageProperties().getRedelivered();

            /*
             * 核心操作失败： 返回 NACK 信息
             * requeue 参数： 控制消息是否重新放回队列
             *  true:   重新放回队列，broker 会重新投递这个消息
             *  false:  不重新放回队列，broker 会丢弃这个消息
             *
             */
            if (redelivered) {
                // 如果当前消息已经是重复投递的，说明此前已经重试过一次了，此处可以选择不同的操作。比如重试几次，或重试几次不成功后直接记录日志
                // 此处requeue设置为false，标识不重新放回队列
                channel.basicNack(deliveryTag, false, false);
            }
            //重试 如果当前消息是第一次投递，说明当前代码是第一次抛异常，尚未重试，所以requeue设置为true，表示重新放回队列
            channel.basicNack(deliveryTag, false, true);
        }
    }

}
